package com.xxx.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 * 注解式的切面类（即将声明式里的连接点通过代码方式表示）
 * 需要在spring配置文件里开启aop注解支持：<aop:aspectj-autoproxy/>
 */
@Aspect
public class AopAspectJ {
	
	/**
	 * 方式2：也可以先定义切点，然后在增强方法前引入切点引用
	 */
//	@Pointcut("execution(* com.xxx.service.impl.Demo*.*(..))")
//  public void pointCut(){}

	/**
	 * 切面的前置方法 即方法执行前拦截到的方法 在目标方法执行之前的通知
	 * @param jp
	 */
//	@Before("pointCut()") // 方式2：引入切点
	@Before("execution(* com.xxx.service.impl.Demo*.*(..))")
	public void doBefore(JoinPoint jp) {
		System.out.println("=========执行前置通知==========");
	}

	/**
	 * 在方法正常执行通过之后执行的通知叫做返回通知 可以返回到方法的返回值 在注解后加入returning
	 * @param jp
	 * @param result
	 */
	@AfterReturning(value = "execution(* com.xxx.service.impl.Demo*.*(..))", returning = "result")
	public void doAfterReturning(JoinPoint jp, String result) {
		System.out.println("===========执行后置通知============");
	}

	/**
	 * 最终通知：目标方法调用之后执行的通知（无论目标方法是否出现异常均执行）
	 * @param jp
	 */
	@After(value = "execution(* com.xxx.service.impl.Demo*.*(..))")
	public void doAfter(JoinPoint jp) {
		System.out.println("===========执行最终通知============");
	}

	/**
	 * 环绕通知：目标方法调用前后执行的通知，可以在方法调用前后完成自定义的行为。
	 * 除环绕增强外，所有的连接点使用的都是 JoinPoint 类型的入参，而环绕增强使用的是 ProceedingJoinPoint。
	 * @param pjp
	 * @return
	 * @throws Throwable
	 */
	@Around("execution(* com.xxx.service.impl.Demo*.*(..))")
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("======执行环绕通知开始=========");
		// 调用方法的参数
		Object[] args = pjp.getArgs();
		// 调用的方法名
		String method = pjp.getSignature().getName();
		// 获取目标对象
		Object target = pjp.getTarget();
		// 执行完方法的返回值
		// 调用proceed()方法，就会触发切入点方法执行
		Object result = pjp.proceed();
		System.out.println("输出,方法名：" + method + ";目标对象：" + target + ";返回值：" + result);
		System.out.println("======执行环绕通知结束=========");
		return result;
	}

	/**
	 * 在目标方法非正常执行完成, 抛出异常的时候会走此方法
	 * @param jp
	 * @param ex
	 */
	@AfterThrowing(value = "execution(* com.xxx.service.impl.Demo*.*(..))", throwing = "ex")
	public void doAfterThrowing(JoinPoint jp, Exception ex) {
		System.out.println("===========执行异常通知============");
	}
}
